package game;

import util.DebugOut;
import game.model.Card;

/**
 * Contains all information about the current state of a player.<br/>
 * <b>"Note: this class has a natural ordering that is inconsistent with equals."</b>
 * @author Witthold/Korol
 */
public class Player implements Comparable<Player>{
	
	/** Name of the player */
	private String name;
	
	/** Buy in or if it is doyle's game stack size */
	protected int cashInit;
	
	/** Position of player in the first hand (0: first player behind the button; 1: second player behind the button; ...)*/
	private int initPosition;
	
	/** Amount of cash the player had at the beginning of the hand */
	private int cashAtStartOfHand;
	
	/** Current cash (current bet is already subtracted) */
	protected int cashCurrent;
	
	/** Position in this hand (0: first player behind the button; 1: second player behind the button; ...) */
	private int currentPosition;
	
	/** Amount of money the player has currently put in the pot */
	private int bet;
	
	/** If the player is folded */
	private boolean folded = false;
	
	/** Hole cards of the player if they are known */
	private Card[] holeCards;

	
	/**
	 * Creates a new player with the given name. Initial & current cash are set accordingly. 
	 * @param name 
	 * 			players name
	 * @param money 
	 * 			initial cash of the player
	 */
	public Player(String name, int money) {
		
		this.name = name;
		this.cashInit = money;
		this.cashCurrent = money;
	}

	/**
	 * @return
	 * 			The player's name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param initPosition
	 * 			The position of the player in the first hand 
	 * 			(0: first player behind the button; 1: second player behind the button; ...)
	 */
	public void setInitPosition(int initPosition) {
		this.initPosition = initPosition;
	}

	/**
	 * @return
	 * 			The position of the player in the first hand
	 * 			(0: first player behind the button; 1: second player behind the button; ...)
	 */
	public int getInitPosition() {
		return initPosition;
	}

	/**
	 * @param cash
	 * 			Amount of cash at the beginning of the hand
	 */
	public void setCashAtStartOfHand(int cash) {
		this.cashAtStartOfHand = cash;
	}

	/**
	 * @return	Amount of cash at the beginning of the hand
	 */
	public int getCashAtStartOfHand() {
		return cashAtStartOfHand;
	}

	/**
	 * @param position
	 * 			Position of the player in this hand
	 * 			(0: first player behind the button; 1: second player behind the button; ...)
	 */
	public void setCurrentPosition(int position) {
		currentPosition = position;
	}

	/**
	 * @return	Position of the player in this hand
	 * 			(0: first player behind the button; 1: second player behind the button; ...)
	 */
	public int getCurrentPosition() {
		return currentPosition;
	}

	/**
	 * @return	Current amount of cash the player has left. Current bets are not included.
	 */
	public int getCurrentCash() {
		return cashCurrent;
	}

	/**
	 * Adds the given amount of money to the own bet and decreases the current cash accordingly  
	 * @param bet
	 * 			Amount of bet increasing
	 */
	public void addBet(int bet) {

		cashCurrent -= bet;
		this.bet += bet;
	}

	/**
	 * @return	The total amount set by the player in this hand
	 */
	public int getCurrentBet() {
		return bet;
	}

	/**
	 * @param cards
	 * 			The hole cards of the player
	 */
	public void setHoleCards(Card[] cards) {
		
		holeCards = cards;
	}

	/**
	 * @return	The hole cards of the player (or null if they aren't set)
	 */
	public Card[] getHoleCards() {
		
		return holeCards;
	}

	/**
	 * Returns if the player isn't folded AND isn't all in.
	 * @return	true if player is active; false if player is folded or all-in
	 */
	public boolean isActive() {
	
		if( folded || isAllIn() ) {
			
			return false;
		
		} else {
			
			return true;
		}
	}

	/**
	 * Returns if the player's current cash is equals 0.
	 * @return	true if the player is all-in
	 */
	public boolean isAllIn() {
		
		return cashCurrent == 0;
	}

	/**
	 * Returns if the player is folded 
	 * @return	true if the player is folded
	 */
	public boolean isFolded() {
		
		return folded;
	}

	/**
	 * Resets the player for a new hand.
	 */
	public void reset() {
		
		bet = 0;
		
		folded = false;
		
		holeCards = null;
	}


	/**
	 * Applies action to the player. (Sets him folded or applies the money change)
	 * @param action
	 * 			The action which is to be applied
	 */
	public void applyAction(Action action) {
		
		if( action.isFold() ) {
	
			fold();
			
		} else {
	
			addBet( action.getChange() );
		}
	}


	/**
	 * Adds the given amount to the player's current cash.
	 * @param amount
	 * 			Amount of cash which is to be added
	 */
	public void addCash(int amount) {
	
		cashCurrent += amount;
	}


	/**
	 * Marks the player as folded.
	 */
	public void fold() {
		
		folded = true;
	}


	/**
	 * Compares the player to another by the profit of the players.
	 */
	@Override
	public int compareTo(Player player) {

		return cashCurrent - cashInit - ( player.getCurrentCash() - player.getInitCash() );
	}

	/**
	 * Prints the player's data to the console.
	 */
	public void printPlayerData() {
		
		DebugOut.showVerbosePlayer("Player: " + name);
		DebugOut.showVerbosePlayer("Buy in: " + cashInit);
		DebugOut.showVerbosePlayer("Init position: " + initPosition);
		DebugOut.showVerbosePlayer("Current position: " + currentPosition);
		DebugOut.showVerbosePlayer("Cash at start of hand: " + cashAtStartOfHand);
		
		DebugOut.showVerbosePlayer("Current cash :" + cashCurrent);
		DebugOut.showVerbosePlayer("Bet :" + bet);
		
		if( holeCards != null ) {
			
			StringBuffer strBuffer = new StringBuffer();
			
			for (Card card : holeCards) {
				
				strBuffer.append(card.toString());
			}

			DebugOut.showVerbosePlayer("HoleCards :" + strBuffer);
		}
	}

	/**
	 * @return	The amount of cash the player had have at the begin of the competition
	 */
	public int getInitCash() {

		return cashInit;
	}
}